﻿using System;
using System.Diagnostics;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.IO;
//using System.Math;
using Microsoft.Kinect;
using Microsoft.Win32;
using Kinect.Toolbox;
using Kinect.Toolbox.Gestures;
using System.Threading;
using System.Threading.Tasks;
using Kinect.Toolbox.Record;
using Kinectver1._0;
using SharpGL;
using SharpGL.WPF;
using SharpGL.Serialization;
using SharpGL.RenderContextProviders;
using SharpGL.SceneGraph;
using SharpGL.SceneGraph.Primitives;
using SharpGL.SceneGraph.Quadrics;
using SharpGL.SceneGraph.Core;
using SharpGL.OpenGLAttributes;
using SharpGL.Enumerations;
using SharpGL.SceneGraph.Effects;

namespace Kinectver1._0.CadObject
{

    public abstract class cadObject
    {
        string name;

        //kinect storrage
        protected List<Vector3> shapePoints = new List<Vector3>(); // Holds all the points of the object, 

        protected Vector3 origin;

        // 
        public int numVerticies { get; set; }
        public int numFaces { get; set; }
        public int numEdges { get; set; }

        public Polygon OFFobj = new Polygon();

        public int objType = 0;

        public uint displayList { get; set; }

        //Transformation Variables
        public string translateString;
        public string rotateString;
        public string scaleString;
        public string resizeString;
        public string mirrorString;
        public string colorString;
        public string hullString;

        public bool is_selected { get; set; }


        //collected verticies
        public List<Vertex> verts = new List<Vertex>();
        //collected polygons
        public List<Face> faces = new List<Face>();
        //opengl hints
        public List<List<Face>> hints = new List<List<Face>>();

        public Vector3 Origin
        {
            set { origin = value; }
            get { return origin; }
        }

        public List<Vector3> getPoints //returns points in the shape BUT NOT the Origin
        {
            get { return shapePoints; }
        }

        public string Name
        {
            get { return name; }
            set { name = value; }
        }

        //this function will be the template for everyone else
        //public abstract void kinectWorldToScene();

        public void updateOrigin(Vector3 newposistion)
        {
            this.Origin = newposistion;
        }

        public void translate(double x, double y, double z)
        {
            translateString = "translate([" + x.ToString() + ", " + y.ToString() + ", " + z.ToString() + "])\n";
        }

        public void rotate(double x, double y, double z)
        {
            rotateString = "rotate(a = [" + x.ToString() + ", " + y.ToString() + ", " + z.ToString() + "])\n";
        }

        public void scale(double x, double y, double z)
        {
            scaleString = "scale([" + x.ToString() + ", " + y.ToString() + ", " + z.ToString() + "])\n";
        }

        public void resize(double x, double y, double z)
        {
            resizeString = "resize([" + x.ToString() + ", " + y.ToString() + ", " + z.ToString() + "]), auto)\n";
        }

        public void mirror(double x, double y, double z)
        {
            mirrorString = "mirror([" + x.ToString() + ", " + y.ToString() + ", " + z.ToString() + "])\n";
        }

        public void color(double r, double b, double g)
        {
            colorString = "color([" + r.ToString() + ", " + b.ToString() + ", " + g.ToString() + "])\n";
        }

        public void hull()
        {
            hullString = "hull()\n";
        }
        protected cadObject()
        {
            this.Origin = new Vector3(0.0f, 0.0f, 0.0f);
            this.OFFobj.Material = new SharpGL.SceneGraph.Assets.Material();
            this.OFFobj.Material.Diffuse = System.Drawing.Color.FromName("White");
            this.is_selected = false;

        }
        protected cadObject(Vector3 pos)
        {
            this.Origin = pos;
            this.OFFobj.Material = new SharpGL.SceneGraph.Assets.Material();
            this.OFFobj.Material.Diffuse = System.Drawing.Color.FromName("White");
            this.is_selected = false;
        }

        //yougns attempts for camera stuff
        public void doTranslate(Vector3 left, Vector3 right)
        {
            double deltax = left.X - right.X;
            double deltay = left.Y - right.Y;
            double deltaz = left.Z - right.Z;

            if (objType == 0) //polygon, off, cube
            {
                if (deltay > 0.2f)
                   this.OFFobj.Transformation.TranslateX -= 0.1f;
                else if (deltay < -0.2f)
                    this.OFFobj.Transformation.TranslateX += 0.1f;

                if (deltax < -0.65f)
                    this.OFFobj.Transformation.TranslateY += 0.1f;
                else if (deltax > -0.25f)
                    this.OFFobj.Transformation.TranslateY -= 0.1f;

                if (deltaz > 0.32f)
                    this.OFFobj.Transformation.TranslateZ -= 0.1f;
                else if (deltaz < -0.1f)
                    this.OFFobj.Transformation.TranslateZ += 0.1f;

                translate(this.OFFobj.Transformation.TranslateX, this.OFFobj.Transformation.TranslateY, this.OFFobj.Transformation.TranslateZ);
            }
            //else if ( objType == 1) //sphere
            //{
            //    if (deltay > 0.2f)
            //        ((Sphere)this.OFFobj[this.objType]).Transformation.TranslateX -= 0.1f;
            //    else if (deltay < -0.2f)
            //        ((Sphere)this.OFFobj[this.objType]).Transformation.TranslateX += 0.1f;

            //    if (deltax < -0.65f)
            //        ((Sphere)this.OFFobj[this.objType]).Transformation.TranslateY += 0.1f;
            //    else if (deltax > -0.25f)
            //        ((Sphere)this.OFFobj[this.objType]).Transformation.TranslateY -= 0.1f;

            //    if (deltaz > 0.32f)
            //        ((Sphere)this.OFFobj[this.objType]).Transformation.TranslateZ -= 0.1f;
            //    else if (deltaz < -0.1f)
            //        ((Sphere)this.OFFobj[this.objType]).Transformation.TranslateZ += 0.1f;

            //    translate(((Cylinder)this.OFFobj[this.objType]).Transformation.TranslateX, ((Cylinder)this.OFFobj[this.objType]).Transformation.TranslateY, ((Cylinder)this.OFFobj[this.objType]).Transformation.TranslateZ);
            //}
            //else //cylinder
            //{
            //    if (deltay > 0.2f)
            //        this.cObj.Transformation.TranslateX -= 0.1f;
            //    else if (deltay < -0.2f)
            //        this.cObj.Transformation.TranslateX += 0.1f;

            //    if (deltax < -0.65f)
            //        this.cObj.Transformation.TranslateY += 0.1f;
            //    else if (deltax > -0.25f)
            //        this.cObj.Transformation.TranslateY -= 0.1f;

            //    if (deltaz > 0.32f)
            //        this.cObj.Transformation.TranslateZ -= 0.1f;
            //    else if (deltaz < -0.1f)
            //        this.cObj.Transformation.TranslateZ += 0.1f;

            //    translate(this.cObj.Transformation.TranslateX, this.cObj.Transformation.TranslateY, this.cObj.Transformation.TranslateZ);
            //}
            
        }

        public void doRotate(Vector3 left, Vector3 right)
        {

            float angleInDegrees = 0.0f;
            double deltax = left.X - right.X;
            double deltay = left.Y - right.Y;
            double deltaz = left.Z - right.Z;

            angleInDegrees = (float)Math.Atan2(deltay, deltax);
            //found the angle. 
            //if your left hand is higher, the angle is positive
            //right hand is higher angle is negative
            //the x distance is about .38f for resting hands.. so..
            if (objType == 0)
            {
                if (deltay > 0.2f)
                   this.OFFobj.Transformation.RotateX -= 1;
                else if (deltay < -0.2f)
                   this.OFFobj.Transformation.RotateX += 1;

                if (deltax < -0.65f)
                    this.OFFobj.Transformation.RotateY -= 1;
                else if (deltax > -0.25f)
                    this.OFFobj.Transformation.RotateY += 1;

                if (deltaz > 0.32f)
                    this.OFFobj.Transformation.RotateZ -= 1;
                else if (deltaz < -0.1f)
                   this.OFFobj.Transformation.RotateZ += 1;

                rotate(this.OFFobj.Transformation.RotateX, this.OFFobj.Transformation.RotateY, this.OFFobj.Transformation.RotateZ);
            }
            //else if (objType == 1)
            //{
            //    if (deltay > 0.2f)
            //        ((Sphere)this.OFFobj[this.objType]).Transformation.RotateX -= 1;
            //    else if (deltay < -0.2f)
            //        ((Sphere)this.OFFobj[this.objType]).Transformation.RotateX += 1;

            //    if (deltax < -0.65f)
            //        ((Sphere)this.OFFobj[this.objType]).Transformation.RotateY -= 1;
            //    else if (deltax > -0.25f)
            //        ((Sphere)this.OFFobj[this.objType]).Transformation.RotateY += 1;

            //    if (deltaz > 0.32f)
            //        ((Sphere)this.OFFobj[this.objType]).Transformation.RotateZ -= 1;
            //    else if (deltaz < -0.1f)
            //        ((Sphere)this.OFFobj[this.objType]).Transformation.RotateZ += 1;

            //    rotate(((Sphere)this.OFFobj[this.objType]).Transformation.RotateX, ((Sphere)this.OFFobj[this.objType]).Transformation.RotateY, ((Sphere)this.OFFobj[this.objType]).Transformation.RotateZ);
            //}
            //else
            //{
            //    if (deltay > 0.2f)
            //        ((Cylinder)this.OFFobj[this.objType]).Transformation.RotateX -= 1;
            //    else if (deltay < -0.2f)
            //        ((Cylinder)this.OFFobj[this.objType]).Transformation.RotateX += 1;

            //    if (deltax < -0.65f)
            //        ((Cylinder)this.OFFobj[this.objType]).Transformation.RotateY -= 1;
            //    else if (deltax > -0.25f)
            //        ((Cylinder)this.OFFobj[this.objType]).Transformation.RotateY += 1;

            //    if (deltaz > 0.32f)
            //        ((Cylinder)this.OFFobj[this.objType]).Transformation.RotateZ -= 1;
            //    else if (deltaz < -0.1f)
            //        ((Cylinder)this.OFFobj[this.objType]).Transformation.RotateZ += 1;

            //    rotate(((Cylinder)this.OFFobj[this.objType]).Transformation.RotateX, ((Cylinder)this.OFFobj[this.objType]).Transformation.RotateY, ((Cylinder)this.OFFobj[this.objType]).Transformation.RotateZ);
            //}
        }
        public void doScale(Vector3 left, Vector3 right)
        {
            double deltax = left.X - right.X;
            double deltay = left.Y - right.Y;
            double deltaz = left.Z - right.Z;

            if (objType == 0)
            {
                if (deltay > 0.2f)
                    this.OFFobj.Transformation.ScaleX -= 0.01f;
                else if (deltay < -0.2f)
                    this.OFFobj.Transformation.ScaleX += 0.01f;

                if (deltax < -0.65f)
                   this.OFFobj.Transformation.ScaleY += 0.01f;
                else if (deltax > -0.25f)
                    this.OFFobj.Transformation.ScaleY -= 0.01f;

                if (deltaz > 0.32f)
                    this.OFFobj.Transformation.ScaleZ -= 0.01f;
                else if (deltaz < -0.1f)
                    this.OFFobj.Transformation.ScaleZ += 0.01f;

                scale(this.OFFobj.Transformation.ScaleX, this.OFFobj.Transformation.ScaleY, this.OFFobj.Transformation.ScaleZ);
            }
            //else if (objType == 1)
            //{
            //    if (deltay > 0.2f)
            //        ((Sphere)this.OFFobj[this.objType]).Transformation.ScaleX -= 0.01f;
            //    else if (deltay < -0.2f)
            //        ((Sphere)this.OFFobj[this.objType]).Transformation.ScaleX += 0.01f;

            //    if (deltax < -0.65f)
            //        ((Sphere)this.OFFobj[this.objType]).Transformation.ScaleY += 0.01f;
            //    else if (deltax > -0.25f)
            //        ((Sphere)this.OFFobj[this.objType]).Transformation.ScaleY -= 0.01f;

            //    if (deltaz > 0.32f)
            //        ((Sphere)this.OFFobj[this.objType]).Transformation.ScaleZ -= 0.01f;
            //    else if (deltaz < -0.1f)
            //        ((Sphere)this.OFFobj[this.objType]).Transformation.ScaleZ += 0.01f;

            //    scale(((Sphere)this.OFFobj[this.objType]).Transformation.ScaleX, ((Sphere)this.OFFobj[this.objType]).Transformation.ScaleY, ((Sphere)this.OFFobj[this.objType]).Transformation.ScaleZ);
            //}
            //else
            //{
            //    if (deltay > 0.2f)
            //        ((Cylinder)this.OFFobj[this.objType]).Transformation.ScaleX -= 0.01f;
            //    else if (deltay < -0.2f)
            //        ((Cylinder)this.OFFobj[this.objType]).Transformation.ScaleX += 0.01f;

            //    if (deltax < -0.65f)
            //        ((Cylinder)this.OFFobj[this.objType]).Transformation.ScaleY += 0.01f;
            //    else if (deltax > -0.25f)
            //        ((Cylinder)this.OFFobj[this.objType]).Transformation.ScaleY -= 0.01f;

            //    if (deltaz > 0.32f)
            //        ((Cylinder)this.OFFobj[this.objType]).Transformation.ScaleZ -= 0.01f;
            //    else if (deltaz < -0.1f)
            //        ((Cylinder)this.OFFobj[this.objType]).Transformation.ScaleZ += 0.01f;

            //    scale(((Cylinder)this.OFFobj[this.objType]).Transformation.ScaleX, ((Cylinder)this.OFFobj[this.objType]).Transformation.ScaleY, ((Cylinder)this.OFFobj[this.objType]).Transformation.ScaleZ);
            //}

            
        }



        public void setOrigin(Vector3 left, Vector3 right)
        {
            double deltax = left.X - right.X;
            double deltay = left.Y - right.Y;
            double deltaz = left.Z - right.Z;

            //OFFobj.Radius = 0.01f;
            if (deltay > 0.2f)
                this.OFFobj.Transformation.TranslateX -= 0.1f;
            else if (deltay < -0.2f)
                this.OFFobj.Transformation.TranslateX += 0.1f;

            if (deltax < -0.65f)
                this.OFFobj.Transformation.TranslateY += 0.1f;
            else if (deltax > -0.25f)
                this.OFFobj.Transformation.TranslateY = 0.1f;

            if (deltaz > 0.32f)
                this.OFFobj.Transformation.TranslateZ -= 0.1f;
            else if (deltaz < -0.1f)
                this.OFFobj.Transformation.TranslateZ += 0.1f;

            //translate(this.obj.Transformation.TranslateX, this.obj.Transformation.TranslateY, this.obj.Transformation.TranslateZ);
        }

        public abstract string toScad();

        public void toOff()
        {
            StreamWriter sw = new StreamWriter(@"C:\Program Files (x86)\KinectCAD\output.scad");

            sw.Write(this.toScad());

            sw.Close();

            ProcessStartInfo newProc = new ProcessStartInfo();
            //newProc.UseShellExecute = true;
            newProc.FileName = @"C:\Program Files (x86)\OpenSCAD\openscad.exe";
            newProc.CreateNoWindow = true;
            newProc.Arguments = "-o \"C:\\Program Files (x86)\\KinectCAD\\input.off\" \"C:\\Program Files (x86)\\KinectCAD\\output.scad\"";
            newProc.WindowStyle = ProcessWindowStyle.Normal;

            try
            {
                using (Process exe = Process.Start(newProc))
                {
                    exe.WaitForExit();
                }
                
            }
            catch
            {

                return;
            }          
            
            //(@"C:\Program Files (x86)\OpenSCAD\openscad.exe");
            

            offObject tmp = new offObject(@"C:\Program Files (x86)\KinectCAD\input.off");
            this.OFFobj = tmp.OFFobj;
            this.OFFobj = this.OFFobj;

            return;
        }
    }


    public class Circle : cadObject
    {
        private double radius;

        public Circle(Vector3 origin)
            : base(origin)
        {
            offObject tmp = new offObject(@"C:\Program Files (x86)\OpenSCAD\cylinder1by1by1.off");// one by one
            this.OFFobj = tmp.OFFobj;
            this.OFFobj = this.OFFobj;

            this.OFFobj.Transformation.ScaleX = 1.0f;
            this.OFFobj.Transformation.ScaleY = 1.0f;
            this.OFFobj.Transformation.ScaleZ = 0.1f;
           
            //this.OFFobj.BaseRadius = 1.0f;
            //this.OFFobj.TopRadius = 1.0f;
            //this.OFFobj.Height = 0.1f;
            //this.OFFobj.QuadricDrawStyle = DrawStyle.Fill;
           
        }

        public void endPoint(Vector3 pos) // Called when the position from the hand is used for creating the circle
        {
            shapePoints.Add(pos); //Adds the first point

            //Calculate the radius based off of origin and given radius
            double xd = Math.Abs(origin.X - pos.X);
            double yd = Math.Abs(origin.Y - pos.Y);
            double zd = Math.Abs(origin.Z - pos.Z);

            this.Radius = Math.Sqrt(xd * xd + yd * yd + zd * zd);

            //Adds remaining points for OpenGL NOTE: This will add an overlapping point to the shape, which is needed for a closed circle
            for (int i = 0; i <= 72; i++)
            {
                shapePoints.Add(new Vector3(origin.X + (float)Radius * (float)Math.Cos(i * .0873), origin.Y + (float)Radius * (float)Math.Sin(i * .0873), origin.Z));
            }


            return;
        }

        public void endPoint(float rad) // Called when a circle is made and a the user provides a radius.
        {
            this.Radius = rad;

            Vector3 newPoint = new Vector3(origin.X + (float)Radius, origin.Y, origin.Z); // adds the first point 

            shapePoints.Add(newPoint);

            //Adds remaining points for OpenGL NOTE: This will add an overlapping point to the shape, which is needed for a closed circle
            for (int i = 0; i <= 72; i++)
            {
                newPoint = new Vector3(origin.X + (float)Radius * (float)Math.Cos(i * .0873), origin.Y + (float)Radius * (float)Math.Sin(i * .0873), origin.Z);
            }

            return;
        }

        public double Radius
        {
            get { return radius; }
            set { radius = value; }
        }

        public override string toScad()
        {
            string value = "";

            if (translateString != null)
            {
                value += translateString;
            }

            if (rotateString != null)
            {
                value += rotateString;
            }

            if (scaleString != null)
            {
                value += scaleString;
            }

            if (resizeString != null)
            {
                value += resizeString;
            }

            if (mirrorString != null)
            {
                value += mirrorString;
            }

            if (colorString != null)
            {
                value += colorString;
            }

            if (hullString != null)
            {
                value += hullString;
            }

            value += "circle(d = 1, $fn = 100);\n";
            return value;
        }
        //public override void kinectWorldToScene()
        //{

        //}
    }

    public class Square : cadObject
    {
        private double length;
        private double height;

        public Square(Vector3 origin)
            : base(origin)//Constuctor that takes the start point of the gesture as the orgin and saves it
        {
            offObject tmp = new offObject(@"C:\Program Files (x86)\OpenSCAD\cube1by1by1.off");// one by one
            this.OFFobj = tmp.OFFobj;
            this.OFFobj = this.OFFobj;
            this.OFFobj.Transformation.ScaleX = 1.0f;
            this.OFFobj.Transformation.ScaleY = 1.0f;
            this.OFFobj.Transformation.ScaleZ = 0.1f;
            
        }

        //public void endPoint(Vector3 lhand, Vector3 rhand) // Fucntion gets the two points required to define the rectangle, and then adds two more point for the other corners.
        //{
        //    shapePoints.Clear();
        //    // adds points to an array in an order that OpenGL can handle.
        //    shapePoints.Add(new Vector3(rhand.X * 10, rhand.Y * 10, rhand.Z * 10));
        //    //this needs changing
        //    shapePoints.Add(new Vector3(rhand.X * 10, lhand.Y * 10, lhand.Z * 10));
        //    shapePoints.Add(new Vector3(lhand.X * 10, lhand.Y * 10, lhand.Z * 10));
        //    shapePoints.Add(new Vector3(lhand.X * 10, rhand.Y * 10, lhand.Z * 10));


        //    //sets the length and hieght of the object

        //    this.Length = Math.Abs(lhand.X - rhand.X);
        //    this.Height = Math.Abs(lhand.Y - rhand.Y);

        //    this.OFFobj.Transformation.ScaleX = (float)Height;
        //    this.OFFobj.Transformation.ScaleY = (float)Length;
        //    this.OFFobj.Transformation.ScaleZ = 5.0f;
        //}

        //public double Length
        //{
        //    get { return length; }
        //    set { length = value; }
        //}

        //public double Height
        //{
        //    get { return height; }
        //    set { height = value; }
        //}

        public override string toScad()
        {
            string value = "";

            if (translateString != null)
            {
                value += translateString;
            }

            if (rotateString != null)
            {
                value += rotateString;
            }

            if (scaleString != null)
            {
                value += scaleString;
            }

            if (resizeString != null)
            {
                value += resizeString;
            }

            if (mirrorString != null)
            {
                value += mirrorString;
            }

            if (colorString != null)
            {
                value += colorString;
            }

            if (hullString != null)
            {
                value += hullString;
            }

            value += "square([1,1]);\n";

            return value;
        }
        //public override void kinectWorldToScene()
        //{

        //}
    }

    public class kCylinder : cadObject
    {
        public kCylinder(Vector3 origin)
            : base(origin)
        {
            offObject tmp = new offObject(@"C:\Program Files (x86)\OpenSCAD\cylinder1by1by1.off");// one by one
            this.OFFobj = tmp.OFFobj;
            this.OFFobj = this.OFFobj;
            this.OFFobj.Transformation.ScaleX = 1.0f;
            this.OFFobj.Transformation.ScaleY = 1.0f;
            this.OFFobj.Transformation.ScaleZ = 1.0f;
            
        }

        public override string toScad()
        {
            string value = "";

            if (translateString != null)
            {
                value += translateString;
            }

            if (rotateString != null)
            {
                value += rotateString;
            }

            if (scaleString != null)
            {
                value += scaleString;
            }

            if (resizeString != null)
            {
                value += resizeString;
            }

            if (mirrorString != null)
            {
                value += mirrorString;
            }

            if (colorString != null)
            {
                value += colorString;
            }

            if (hullString != null)
            {
                value += hullString;
            }

            value += "cylinder( h=1, d =1, $fn = 100);\n";

            return value;
        }
    }

    public class kCube : cadObject
    {
        public kCube(Vector3 orgin) : base(orgin)
        {
            offObject tmp = new offObject(@"C:\Program Files (x86)\OpenSCAD\cube1by1by1.off");// one by one
            this.OFFobj = tmp.OFFobj;
            this.OFFobj = this.OFFobj;
            this.OFFobj.Transformation.ScaleX = 1.0f;
            this.OFFobj.Transformation.ScaleY = 1.0f;
            this.OFFobj.Transformation.ScaleZ = 1.0f;
            
        }
        public override string toScad()
        {
            string value = "";

            if (translateString != null)
            {
                value += translateString;
            }

            if (rotateString != null)
            {
                value += rotateString;
            }

            if (scaleString != null)
            {
                value += scaleString;
            }

            if (resizeString != null)
            {
                value += resizeString;
            }

            if (mirrorString != null)
            {
                value += mirrorString;
            }

            if (colorString != null)
            {
                value += colorString;
            }

            if (hullString != null)
            {
                value += hullString;
            }

            value += "cube([1,1,1]);\n";

            return value;
        }
    }

    public class booleanObj : cadObject
    {

        int type; // 0 = union; 1 = difference; 2 = intersection;
        int shCount;
        public List<string> containedShapes = new List<string>();

        public booleanObj(int boolType) // tell it what type of transformation it will be.
            : base()
        {
            type = boolType;
            shCount = 0;
        }

        public override string toScad()
        {
            string value = "";

            if (translateString != null)
            {
                value += translateString;
            }

            if (rotateString != null)
            {
                value += rotateString;
            }

            if (scaleString != null)
            {
                value += scaleString;
            }

            if (resizeString != null)
            {
                value += resizeString;
            }

            if (mirrorString != null)
            {
                value += mirrorString;
            }

            if (colorString != null)
            {
                value += colorString;
            }

            if (hullString != null)
            {
                value += hullString;
            }

            switch (type) // give it the correct string for its type.
            {
                case 1: value += "union(){\n";
                    break;
                case 2: value += "difference(){\n";
                    break;
                case 3: value += "intersection(){\n";
                    break;
            };

            for (int i = 0; i < containedShapes.Count; i++)
            {
                value += containedShapes[i];
            }

            value += "};\n";

            return value;
        }

        public void addShape(cadObject shape)
        {
            containedShapes.Add(shape.toScad());
            shCount++;
        }
    }

    public class kSphere : cadObject
    {

        public kSphere(Vector3 orgin)
            : base(orgin)
        {
            offObject tmp = new offObject(@"C:\Program Files (x86)\OpenSCAD\sphere1by1by1.off");// one by one
            this.OFFobj = tmp.OFFobj;
            this.OFFobj = this.OFFobj;
            this.OFFobj.Transformation.ScaleX = 1.0f;
            this.OFFobj.Transformation.ScaleY = 1.0f;
            this.OFFobj.Transformation.ScaleZ = 1.0f;

        }

        public override string toScad()
        {
            string value = "";

            if (translateString != null)
            {
                value += translateString;
            }

            if (rotateString != null)
            {
                value += rotateString;
            }

            if (scaleString != null)
            {
                value += scaleString;
            }

            if (resizeString != null)
            {
                value += resizeString;
            }

            if (mirrorString != null)
            {
                value += mirrorString;
            }

            if (colorString != null)
            {
                value += colorString;
            }

            if (hullString != null)
            {
                value += hullString;
            }

            value += "sphere(d =1, $fn = 100);\n";

            return value;
        }

    }

    //scad object for references
    public class scadObj : cadObject
    {
        public string twoDcmd { get; set; } //"circle (radius | d=diamer);" || "square(2, 2);"

        public string threeDcmd { get; set; }

        public string TransformationCmd { get; set; }

        public string BooleanCmd { get; set; }

        public string lin_ext { get; set; }

        public scadObj()
            : base()
        {

        }

        public override string toScad()
         {
             string value = "";

             if (translateString != null)
             {
                 value += translateString;
             }

             if (rotateString != null)
             {
                 value += rotateString;
             }

             if (scaleString != null)
             {
                 value += scaleString;
             }

             if (resizeString != null)
             {
                 value += resizeString;
             }

             if (mirrorString != null)
             {
                 value += mirrorString;
             }

             if (colorString != null)
             {
                 value += colorString;
             }

             if (hullString != null)
             {
                 value += hullString;
             }

             value += threeDcmd;

             return value;
         }
     }

        //an OFF file object!
        public class offObject : cadObject
        {
            //off file properties
            public string filePath { get; set; }


            //obj properties
            public bool isColored { get; set; }

            //the points will be stored in teh verticies. 
            //so far from what ive witnessed off objects have origin 0,0,0
            public offObject(string file)
            {
                this.filePath = file;
                this.numVerticies = 0;
                this.numFaces = 0;
                this.numEdges = 0;
                this.isColored = false;
                this.Name = "offobj";
                this.objType = 0;
                parseOFF();

            }

            //parse this file!
            public void parseOFF()
            {
                //load file in
                string line;
                string delim = " ";
                string[] tokens;
                using (StreamReader sr = new StreamReader(this.filePath))
                {
                    line = sr.ReadLine();
                    //first line should be OFF
                    if (line != "OFF")
                    {
                        MessageBox.Show("INVALID FILE LOADED");
                        return;
                    }
                    line = sr.ReadLine();
                    tokens = line.Split(delim.ToCharArray());
                    if (tokens.Count() != 3)
                    {
                        MessageBox.Show("invalid file format!");
                        return;
                    }

                    //basic file information is stored in tokens, now parse them out
                    this.numVerticies = Convert.ToInt32(tokens[0]);
                    this.numFaces = Convert.ToInt32(tokens[1]);
                    this.numEdges = Convert.ToInt32(tokens[2]);
                    //quick check
                    if (this.numVerticies == 0 || this.numFaces == 0)
                    {
                        MessageBox.Show("OFF DOES NOT HAVE ENOUGH VERTICES OR POLYGONS");
                        return;
                    }

                    //varabiles are now set. test next line
                    line = sr.ReadLine();

                    //now begin the processing loop!

                    //verticies first
                    for (int i = 0; i < numVerticies; i++)
                    {
                        line = sr.ReadLine();
                        this.verts.Add(getVertex(line.Split(delim.ToCharArray())));
                        this.hints.Add(new List<Face>());
                    }

                    //polygons now
                    for (int j = 0; j < numFaces; j++)
                    {
                        line = sr.ReadLine();
                        getFace(line.Split(delim.ToCharArray()));

                    }
                    //if you get here. the off has been fully processesed

                }
                //normalizethe thing
                this.OFFobj.Validate(true);

                //now check make it renderable

            }
            public Vertex getVertex(string[] tokens)
            {
                Vertex nv;
                //3 poitns are needed
                if (tokens.Count() < 3)
                {
                    MessageBox.Show("invalid vertex count");
                    return new Vertex();
                }
                nv = new Vertex(Convert.ToSingle(tokens[0]) , Convert.ToSingle(tokens[1]), Convert.ToSingle(tokens[2]));
                return nv;
            }
            public Face getFace(string[] tokens)
            {
                int polyVertCount = 0;

                if (tokens.Count() < 4)
                {
                    MessageBox.Show("polygon line not formatted correctly");
                    return null;
                }

                //correct now lets start this off!
                Face nf = new Face();

                polyVertCount = Convert.ToInt32(tokens[0]); //get the number of verticies
                Vertex[] list = new Vertex[polyVertCount];

                for (int i = 0; i < polyVertCount; i++)
                {
                    int j = Convert.ToInt32(tokens[i + 2]); //find which verticie this corresponds too +2 sicne token will give us a space as a token
                    list[i] = (this.verts[j]); //get it and add it!
                }

                this.OFFobj.AddFaceFromVertexData(list);
                //now letsmake the face for this

                return nf;

            }

            public float[] getColorInfo(string[] tokens)
            {
                float[] color = new float[4];

                if (tokens.Count() < 6 || tokens.Count() > 7)
                    return null;

                for (int x = 3; x < tokens.Count(); x++)
                {
                    color[x - 3] = Convert.ToSingle(tokens[x]);
                }

                return color;
            }
            public void createDisplayList(OpenGL gl, float angle)
            {
                int pCount = numFaces;

                displayList = gl.GenLists(1);
                gl.NewList(displayList, (int)OpenGL.GL_COMPILE);
                for (int i = 0; i < pCount; i++)
                {
                    Face nf = faces[i]; //np == new polygon
                    //if smoothed

                    gl.Begin(OpenGL.GL_LINE_LOOP);




                    gl.End();
                }
                gl.EndList();
            }

            public override string toScad()
            {
                return "";
            }

        }

        public class objectManager
        {
            protected List<cadObject> containedShapes; //this is for kinect side using
            public SceneElement treeWrap;



            public cadObject currentSelected;

            int currentCount;
            int totalCount;

            public objectManager()
            {
                currentCount = 0;
                totalCount = 0;
                containedShapes = new List<cadObject>();
            }

            public void getSceneContainer(SceneElement sc)
            {
                treeWrap = sc;
            }

            public void enableCurrentlySelected()
            {
                foreach (var child in treeWrap.Children)
                {
                    if (child.Name == this.currentSelected.OFFobj.Name)
                    {
                        child.IsEnabled = true;
                    }
                }
            }
            public void disableCurrentlySelected()
            {
                foreach (var child in treeWrap.Children)
                {
                    if (child.Name == this.currentSelected.OFFobj.Name)
                    {
                        child.IsEnabled = false;
                    }
                }
            }
            //forreference on getting something and doing something to it
            //public void something()
            //{
            //    foreach (var child in treeWrap.Children)
            //    {
            //        if (child.Name == this.currentSelected.obj.Name)
            //        {
            //            //((Polygon)child).Transformation.TranslateX = 3.0f;

            //        }
            //    }
            //}

            public void addObject(cadObject addition)
            {
                if (addition != null)
                {
                    currentCount++;
                    totalCount++;
                    addition.Name = "Shape" + totalCount;
                    addition.OFFobj.Name = addition.Name;
                    //addition.OFFobj.Name = addition.Name;
                    if (currentSelected != null)
                        currentSelected.OFFobj.Material.Diffuse = System.Drawing.Color.FromName("White");
                    containedShapes.Add(addition);
                    treeWrap.AddChild(addition.OFFobj);
                    treeWrap.Parent.Traverse();


                    currentSelected = containedShapes.Last<cadObject>();

                    //currentSelected.OFFobj.Material.Ambient = System.Drawing.Color.FromName("Red");
                    currentSelected.OFFobj.Material.Diffuse = System.Drawing.Color.FromName("Red");
                }
            }

            public void removeObject(string objName)
            {
                for (int i = 0; i < containedShapes.Count; i++)
                {
                    if (containedShapes[i].Name == objName)
                    {

                        containedShapes.RemoveAt(i);
                        currentCount--;
                    }
                }
            }

            public void previousObject()
            {

                if (containedShapes.Count == 0)
                    return;

                int index = containedShapes.IndexOf(currentSelected);
                if (currentSelected != null && !currentSelected.is_selected)
                    currentSelected.OFFobj.Material.Diffuse = System.Drawing.Color.FromName("White");

                if (index == 0)
                {
                    index = containedShapes.Count - 1;
                }

                else
                {
                    index -= 1;
                }


                currentSelected = containedShapes[index];
                if (!currentSelected.is_selected)
                    currentSelected.OFFobj.Material.Diffuse = System.Drawing.Color.FromName("Red");
            }
            public void updateViewer(ListView viewer)
            {
                viewer.Items.Clear();
                foreach (cadObject obj in containedShapes)
                {
                    viewer.Items.Add(obj.Name);
                    if (obj == currentSelected)
                    {

                        viewer.SelectedIndex = viewer.Items.Count - 1;
                    }
                    //need to work on currently selected stuff
                }

            }
            public void nextObject()
            {

                if (containedShapes.Count == 0)
                    return;

                int index = containedShapes.IndexOf(currentSelected);

                if (currentSelected != null && !currentSelected.is_selected)
                    currentSelected.OFFobj.Material.Diffuse = System.Drawing.Color.FromName("White");

                if (index == containedShapes.Count - 1)
                {

                    index = 0;
                }
                else
                {
                    index += 1;
                }

                currentSelected = containedShapes[index];
                if (!currentSelected.is_selected)
                    currentSelected.OFFobj.Material.Diffuse = System.Drawing.Color.FromName("Red");
            }
            //public cadObject grabber
            public int Count
            {
                get { return currentCount; }
                set { currentCount = value; }
            }

            public List<cadObject> Objects
            {
                get { return containedShapes; }
            }

        }

        //A class for later, non-function requirement for the proto-type.
        //public class Polygon : cadObject
        //{
        // can't handle convex shapes.
        //}
    
}
